package com.ubb.smartsearch.controller;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import com.ubb.smartsearch.classifier.ClassifierInterface;
import com.ubb.smartsearch.controller.exception.SearchGoneWrongException;
import com.ubb.smartsearch.searchengineif.AccessLocal;
import com.ubb.smartsearch.searchengineif.XMLResultParserLocal;
import com.ubb.smartsearch.searchengineif.entity.Response;
import com.ubb.smartsearch.searchengineif.entity.Result;
import com.ubb.smartsearch.searchengineif.entity.Search;
import com.ubb.smartsearch.searchengineif.exception.FieldParsingException;

@Stateless
public class SearchHandlerBean implements SearchHandlerLocal {

	private static Logger logger = Logger.getLogger(SearchHandlerBean.class
			.getName());

	@EJB(beanName="FarooAccess")
	private AccessLocal farooAccess;
	@EJB(beanName="FarooXMLResultParser")
	private XMLResultParserLocal xmlResultParser;

//	@EJB(beanName = "NaiveBayesClassifierBean")
//	private ClassifierInterface bayesClassifier;
//
//	@EJB(beanName = "RocchioClassifierBean")
//	private ClassifierInterface rocchioClassifier;
	
	private ClassifierInterface classifier;

	@PostConstruct
	public void initialize() {
		
		try {
			InitialContext ic = new InitialContext();
			classifier = (ClassifierInterface) ic.lookup("java:global/SmartSearch/SmartSearchClassifier-0.0.1-SNAPSHOT/RocchioClassifierBean");
		} catch (NamingException e) {
			logger.severe(e.getMessage());
		}
		loadTrainData();
	}

	
	public Collection<Result> handleSimpleSearch(String query) {

		Response response = search(query);
		Collection<Result> searchResults = response.getResults();

		return searchResults;
	}
	
	public List<Result> classify(List<Result> results) {

		for(int i=0; i<results.size(); ++i) {
			Result actual = results.get(i);
			String category = classifier.classifyDocument(actual
					.getUrl());
			actual.setCategory(category);
			results.set(i, actual);
		}

		return results;
	}
	
//	public List<Result> classifyWithBayes(List<Result> results) {
//
//		for(int i=0; i<results.size(); ++i) {
//			Result actual = results.get(i);
//			String category = classifier.classifyDocument(actual
//					.getUrl());
//			actual.setCategory(category);
//			results.set(i, actual);
//		}
//
//		return results;
//	}
	
//	public List<Result> classifyWithRocchio(List<Result> results) {
//
//		for(int i=0; i<results.size(); ++i) {
//			Result actual = results.get(i);
//			String category = classifier.classifyDocument(actual
//					.getUrl());
//			actual.setCategory(category);
//			results.set(i, actual);
//		}
//
//		return results;
//	}

	private Response search(String query) throws SearchGoneWrongException {

		Search search = new Search();
		search.setQ(query);
		search.setF("xml");
		search.setLength(100);

		String url = null;
		try {
			url = farooAccess.buildURLFromSearchEntity(search);
			logger.info("The builded URL is: " + url);
		} catch (FieldParsingException e) {
			logger.severe(e.getMessage());
			throw new SearchGoneWrongException();
		} catch (UnsupportedEncodingException e) {
			logger.severe(e.getMessage());
			throw new SearchGoneWrongException();
		}

		try {
			return xmlResultParser.getResponseFromURL(url);
		} catch (MalformedURLException e) {
			logger.severe(e.getMessage());
		} catch (ParserConfigurationException e) {
			logger.severe(e.getMessage());
		} catch (SAXException e) {
			logger.severe(e.getMessage());
		} catch (IOException e) {
			logger.severe(e.getMessage());
		}

		return null;
	}

	private void loadTrainData() {
			Properties properties = new Properties();
			try {
				properties.load(new FileInputStream(".properties"));
				setRocchioParameters(16, 4);
				train(properties.getProperty("corpusName"));
			} catch (FileNotFoundException e2) {
				train("20newsgroups");
			} catch (IOException e2) {
				logger.severe(e2.getMessage());
			}
	}
//	private void loadRocchioTrainData() {
//		try {
//			rocchioClassifier = Utils
//					.deserializeClassifier("rocchioTrainData.dat");
//		} catch (FileNotFoundException e) {
//			logger.info(e.getMessage());
//			Properties properties = new Properties();
//			try {
//				properties.load(new FileInputStream(".properties"));
//				setRocchioParameters(16, 4);
//				trainRocchio(properties.getProperty("corpusName"));
//			} catch (FileNotFoundException e2) {
//				trainRocchio("20newsgroups");
//			} catch (IOException e2) {
//				logger.severe(e2.getMessage());
//			}
//		} catch (IOException e) {
//			logger.severe(e.getMessage());
//		} catch (ClassNotFoundException e) {
//			logger.severe(e.getMessage());
//		}
//	}

//	private void loadBayesTrainData() {
//		try {
//			bayesClassifier = Utils.deserializeClassifier("bayesTrainData.dat");
//		} catch (FileNotFoundException e) {
//			logger.info(e.getMessage());
//			Properties properties = new Properties();
//			try {
//				properties.load(new FileInputStream(".properties"));
//				trainBayes(properties.getProperty("corpusName"));
//			} catch (FileNotFoundException e2) {
//				trainBayes("20newsgroups");
//			} catch (IOException e2) {
//				logger.severe(e2.getMessage());
//			}
//		} catch (IOException e) {
//			logger.severe(e.getMessage());
//		} catch (ClassNotFoundException e) {
//			logger.severe(e.getMessage());
//		}
//	}

	public void train(String corpus) {
		try {
			classifier.trainCategories(corpus);
		} catch (IOException e) {
			logger.severe(e.getMessage());
		}
	}
//	public void trainBayes(String corpus) {
//		try {
//			classifier.trainCategories(corpus);
//		} catch (IOException e) {
//			logger.severe(e.getMessage());
//		}

//		try {
//			Utils.serializeClassifier(bayesClassifier, "bayesTrainData.dat");
//		} catch (FileNotFoundException e) {
//			logger.severe(e.getMessage());
//		} catch (IOException e) {
//			logger.severe(e.getMessage());
//		}
//	}

//	public void trainRocchio(String corpus) {
//		try {
//			classifier.trainCategories(corpus);
//		} catch (IOException e) {
//			logger.severe(e.getMessage());
//		}

//		try {
//			Utils.serializeClassifier(rocchioClassifier, "rocchioTrainData.dat");
//		} catch (FileNotFoundException e) {
//			logger.severe(e.getMessage());
//		} catch (IOException e) {
//			logger.severe(e.getMessage());
//		}
//	}

	public void setRocchioParameters(double alfa, double beta) {
		classifier.setRocchioParameters(alfa, beta);
	}


	public void changeAlgorithm(String selectedAlgorithm, Double alfa, Double beta) {
		try {
			InitialContext ic = new InitialContext();
			if("rocchio".equals(selectedAlgorithm)) {
				classifier = 
						(ClassifierInterface) ic.lookup(
								"java:global/SmartSearch/SmartSearchClassifier-0.0.1-SNAPSHOT/RocchioClassifierBean"
							);
				setRocchioParameters(alfa, beta);
			} else {
				classifier = 
						(ClassifierInterface) ic.lookup(
								"java:global/SmartSearch/SmartSearchClassifier-0.0.1-SNAPSHOT/NaiveBayesClassifierBean"
							);
			}
		} catch (NamingException e) {
			logger.severe(e.getMessage());
		}
	}
}
